package news.tencent.charco.android.view.activity;

import android.Manifest;
import android.media.AudioManager;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.TextView;

import com.alibaba.fastjson.JSONException;
import com.alibaba.fastjson.JSONObject;

import org.webrtc.AudioSource;
import org.webrtc.AudioTrack;
import org.webrtc.Camera1Enumerator;
import org.webrtc.DataChannel;
import org.webrtc.EglBase;
import org.webrtc.IceCandidate;
import org.webrtc.MediaConstraints;
import org.webrtc.MediaStream;
import org.webrtc.PeerConnection;
import org.webrtc.PeerConnectionFactory;
import org.webrtc.RendererCommon;
import org.webrtc.RtpReceiver;
import org.webrtc.SdpObserver;
import org.webrtc.SessionDescription;
import org.webrtc.SurfaceTextureHelper;
import org.webrtc.SurfaceViewRenderer;
import org.webrtc.VideoCapturer;
import org.webrtc.VideoSource;
import org.webrtc.VideoTrack;

import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

import io.socket.client.IO;
import io.socket.client.Socket;
import io.socket.emitter.Emitter;
import me.weyye.hipermission.HiPermission;
import me.weyye.hipermission.PermissionCallback;
import me.weyye.hipermission.PermissionItem;
import news.tencent.charco.android.R;
import news.tencent.charco.android.utils.ToastUtil;

/**
 * @CreateDate: 2019/6/14 17:08
 * @ClassName: RecommendListFragment
 * @Author: Lunatic Princess
 * @Descriptions: 碎片链表，在RecommendFragment中实例化进行界面填充
 */
public class WebrtcActivity extends AppCompatActivity implements View.OnClickListener {

    private LinearLayout chartTools;
    private TextView switcCamera;
    private TextView loundSperaker;

    private SurfaceViewRenderer localView;
    private SurfaceViewRenderer remoteView;
    private EglBase mEglBase;

    private Peer mPeer;
    private PeerConnectionFactory peerConnectionFactory;
    private MediaStream mMediaStream;
    private Socket mSocket;
    private MediaConstraints pcConstraints;
    private MediaConstraints sdpConstraints;
    private LinkedList<PeerConnection.IceServer> iceServers;
    private VideoTrack remoteVideoTrack;
    private AudioManager mAudioManager;

    private boolean isOffer = false;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.view_webrtc);
        initview();
        AskPermission();
    }

    private void AskPermission() {
        List<PermissionItem> permissionItems = new ArrayList<PermissionItem>();

        permissionItems.add(new PermissionItem(Manifest.permission.CAMERA, "相机", R.drawable.permission_ic_camera));
        permissionItems.add(new PermissionItem(Manifest.permission.WRITE_EXTERNAL_STORAGE, "存储卡", R.drawable.permission_ic_storage));
        permissionItems.add(new PermissionItem(Manifest.permission.RECORD_AUDIO, "录音", R.drawable.permission_ic_micro_phone));
        permissionItems.add(new PermissionItem(Manifest.permission.READ_PHONE_STATE, "手机", R.drawable.permission_ic_phone));

        HiPermission.create(this).permissions(permissionItems)
                .checkMutiPermission(new PermissionCallback() {
                    @Override
                    public void onClose() {

                    }

                    @Override
                    public void onFinish() {
                        init();
                    }

                    @Override
                    public void onDeny(String permission, int position) {

                    }

                    @Override
                    public void onGuarantee(String permission, int position) {

                    }
                });
    }

    public void init() {
        // create PeerConnectionFactory
        PeerConnectionFactory.InitializationOptions initializationOptions =
                PeerConnectionFactory.InitializationOptions.builder(getApplicationContext()).createInitializationOptions();
        PeerConnectionFactory.initialize(initializationOptions);
        peerConnectionFactory = PeerConnectionFactory.builder().createPeerConnectionFactory();

        initConstraints();

        MediaConstraints audioConstraints = new MediaConstraints();
        //回声消除
        audioConstraints.mandatory.add(new MediaConstraints.KeyValuePair("googEchoCancellation", "true"));
        //自动增益
        audioConstraints.mandatory.add(new MediaConstraints.KeyValuePair("googAutoGainControl", "true"));
        //高音过滤
        audioConstraints.mandatory.add(new MediaConstraints.KeyValuePair("googHighpassFilter", "true"));
        //噪音处理
        audioConstraints.mandatory.add(new MediaConstraints.KeyValuePair("googNoiseSuppression", "true"));
        // create AudioSource
        AudioSource audioSource = peerConnectionFactory.createAudioSource(audioConstraints);
        AudioTrack audioTrack = peerConnectionFactory.createAudioTrack("101", audioSource);

        SurfaceTextureHelper surfaceTextureHelper = SurfaceTextureHelper.create("CaptureThread", mEglBase.getEglBaseContext());
        // create VideoCapturer
        VideoCapturer videoCapturer = createCameraCapturer();
        VideoSource videoSource = peerConnectionFactory.createVideoSource(videoCapturer.isScreencast());
        videoCapturer.initialize(surfaceTextureHelper, getApplicationContext(), videoSource.getCapturerObserver());
        videoCapturer.startCapture(480, 640, 30);

        // create VideoTrack
        VideoTrack videoTrack = peerConnectionFactory.createVideoTrack("102", videoSource);
        // display in localView
        videoTrack.addSink(localView);

        mMediaStream = peerConnectionFactory.createLocalMediaStream("localstream");
        mMediaStream.addTrack(videoTrack);
        mMediaStream.addTrack(audioTrack);


        //连接服务器
        try {
            mSocket = IO.socket("http://172.19.50.229:6666/");
        } catch (URISyntaxException e) {
            e.printStackTrace();
        }
        mSocket.on("SomeOneOnline", new Emitter.Listener() {
            @Override
            public void call(Object... args) {
                isOffer = true;
                if (mPeer == null) {
                    mPeer = new Peer();
                }
                mPeer.peerConnection.createOffer(mPeer, sdpConstraints);
            }
        }).on("IceInfo", new Emitter.Listener() {
            @Override
            public void call(Object... args) {
                try {
                    org.json.JSONObject jsonObject = new org.json.JSONObject(args[0].toString());
                    IceCandidate candidate = new IceCandidate(
                            jsonObject.getString("id"),
                            jsonObject.getInt("label"),
                            jsonObject.getString("candidate")
                    );
                    mPeer.peerConnection.addIceCandidate(candidate);
                } catch (org.json.JSONException e) {
                    e.printStackTrace();
                }
            }
        }).on("SdpInfo", new Emitter.Listener() {
            @Override
            public void call(Object... args) {
                if (mPeer == null) {
                    mPeer = new Peer();
                }
                try {
                    org.json.JSONObject jsonObject = new org.json.JSONObject(args[0].toString());
                    SessionDescription description = new SessionDescription
                            (SessionDescription.Type.fromCanonicalForm(jsonObject.getString("type")),
                                    jsonObject.getString("description"));
                    mPeer.peerConnection.setRemoteDescription(mPeer, description);
                    if (!isOffer) {
                        mPeer.peerConnection.createAnswer(mPeer, sdpConstraints);
                    }
                } catch (org.json.JSONException e) {
                    e.printStackTrace();
                }
            }
        });
        mSocket.connect();
    }

    private void initview() {

        chartTools = findViewById(R.id.charttools_layout);
        switcCamera = findViewById(R.id.switch_camera_tv);
        loundSperaker = findViewById(R.id.loundspeaker_tv);

        switcCamera.setOnClickListener(this);
        loundSperaker.setOnClickListener(this);

        localView = findViewById(R.id.localVideoView);
        remoteView = findViewById(R.id.remoteVideoView);

        //创建EglBase对象
        mEglBase = EglBase.create();

        //初始化localView
        localView.init(mEglBase.getEglBaseContext(), null);
        localView.setKeepScreenOn(true);
        localView.setMirror(true);
        localView.setZOrderMediaOverlay(true);
        localView.setScalingType(RendererCommon.ScalingType.SCALE_ASPECT_FIT);
        localView.setEnableHardwareScaler(false);

        //初始化remoteView
        remoteView.init(mEglBase.getEglBaseContext(), null);
        remoteView.setMirror(false);
        remoteView.setZOrderMediaOverlay(true);
        remoteView.setScalingType(RendererCommon.ScalingType.SCALE_ASPECT_FIT);
        remoteView.setEnableHardwareScaler(false);

        //关闭扬声器
        mAudioManager = (AudioManager) getSystemService(AUDIO_SERVICE);
        assert mAudioManager != null;
        mAudioManager.setMode(AudioManager.MODE_IN_CALL);
        mAudioManager.setSpeakerphoneOn(false);
    }

    private void initConstraints() {
        iceServers = new LinkedList<>();

//        PeerConnection.IceServer.Builder iceServerBuilder = PeerConnection.IceServer.builder("stun:stun.voipbuster.com:3478");
//        iceServerBuilder.setTlsCertPolicy(PeerConnection.TlsCertPolicy.TLS_CERT_POLICY_INSECURE_NO_CHECK); //this does the magic.
//        PeerConnection.IceServer iceServer =  iceServerBuilder.createIceServer();
//        iceServers.add(iceServer);

//        iceServers.add(PeerConnection.IceServer.builder("stun:23.21.150.121").createIceServer());
        iceServers.add(PeerConnection.IceServer.builder("stun:stun.voipbuster.com:3478").createIceServer());
        iceServers.add(PeerConnection.IceServer.builder("stuns:stun.xten.com:3478").createIceServer());

        pcConstraints = new MediaConstraints();
        pcConstraints.optional.add(new MediaConstraints.KeyValuePair("DtlsSrtpKeyAgreement", "true"));
        pcConstraints.optional.add(new MediaConstraints.KeyValuePair("RtpDataChannels", "true"));


        sdpConstraints = new MediaConstraints();
        sdpConstraints.mandatory.add(new MediaConstraints.KeyValuePair("OfferToReceiveAudio", "true"));
        sdpConstraints.mandatory.add(new MediaConstraints.KeyValuePair("OfferToReceiveVideo", "true"));

    }

    private VideoCapturer createCameraCapturer() {
        Camera1Enumerator enumerator = new Camera1Enumerator(false);
        final String[] deviceNames = enumerator.getDeviceNames();

        // First, try to find front facing camera
        for (String deviceName : deviceNames) {
            if (enumerator.isFrontFacing(deviceName)) {
                VideoCapturer videoCapturer = enumerator.createCapturer(deviceName, null);

                if (videoCapturer != null) {
                    return videoCapturer;
                }
            }
        }

        // Front facing camera not found, try something else
        for (String deviceName : deviceNames) {
            if (!enumerator.isFrontFacing(deviceName)) {
                VideoCapturer videoCapturer = enumerator.createCapturer(deviceName, null);

                if (videoCapturer != null) {
                    return videoCapturer;
                }
            }
        }

        return null;
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.switch_camera_tv:
//                mVideoCapturer.switchCamera(new CameraVideoCapturer.CameraSwitchHandler() {
//                    @Override
//                    public void onCameraSwitchDone(boolean b) {
//                        //切换摄像头完成
//
//                    }
//
//                    @Override
//                    public void onCameraSwitchError(String s) {
//                        //切换摄像头错误
//                    }
//                });
                break;

            case R.id.loundspeaker_tv:
//                if (mAudioManager.isSpeakerphoneOn()) {
//                    mAudioManager.setSpeakerphoneOn(false);
//                    Toast.makeText(this, "扬声器已关闭", Toast.LENGTH_SHORT).show();
//                } else {
//                    mAudioManager.setSpeakerphoneOn(true);
//                    Toast.makeText(this, "扬声器已打开", Toast.LENGTH_SHORT).show();
//                }
                break;
        }

    }

    class Peer implements PeerConnection.Observer, SdpObserver {

        PeerConnection peerConnection;

        Peer() {
            peerConnection = peerConnectionFactory.createPeerConnection(iceServers, this);
            peerConnection.addStream(mMediaStream);
        }

        // PeerConnection.Observer

        @Override
        public void onSignalingChange(PeerConnection.SignalingState signalingState) {
            System.out.println("onSignalingChange");
        }

        @Override
        public void onIceConnectionChange(PeerConnection.IceConnectionState iceConnectionState) {
            if (iceConnectionState == PeerConnection.IceConnectionState.DISCONNECTED) {
                remoteVideoTrack.dispose();
                remoteView.clearImage();
                mPeer = null;
                isOffer = false;
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        ToastUtil.showToast("已断开连接!");
                    }
                });
            }
        }

        @Override
        public void onIceConnectionReceivingChange(boolean b) {
            System.out.println("onIceConnectionReceivingChange");
        }

        @Override
        public void onIceGatheringChange(PeerConnection.IceGatheringState iceGatheringState) {
            System.out.println("onIceGatheringChange");
        }

        @Override
        public void onIceCandidate(IceCandidate iceCandidate) {
            try {
                JSONObject jsonObject = new JSONObject();
                jsonObject.put("label", iceCandidate.sdpMLineIndex);
                jsonObject.put("id", iceCandidate.sdpMid);
                jsonObject.put("candidate", iceCandidate.sdp);
                mSocket.emit("IceInfo", jsonObject.toString());
            } catch (JSONException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onIceCandidatesRemoved(IceCandidate[] iceCandidates) {
            System.out.println("onIceCandidatesRemoved");
        }

        @Override
        public void onAddStream(MediaStream mediaStream) {
            System.out.println("onAddStream");
            remoteVideoTrack = mediaStream.videoTracks.get(0);
            remoteVideoTrack.addSink(remoteView);
//            remoteVideoTrack.addRenderer(new VideoRenderer(remoteView));
        }

        @Override
        public void onRemoveStream(MediaStream mediaStream) {
            System.out.println("onRemoveStream");
        }

        @Override
        public void onDataChannel(DataChannel dataChannel) {
            System.out.println("onDataChannel");
        }

        @Override
        public void onRenegotiationNeeded() {
            System.out.println("onRenegotiationNeeded");
        }

        @Override
        public void onAddTrack(RtpReceiver rtpReceiver, MediaStream[] mediaStreams) {
            System.out.println("onAddTrack");
        }

        //    SdpObserver

        @Override
        public void onCreateSuccess(SessionDescription sessionDescription) {
            peerConnection.setLocalDescription(this, sessionDescription);
            JSONObject jsonObject = new JSONObject();
            try {
                jsonObject.put("type", sessionDescription.type.canonicalForm());
                jsonObject.put("description", sessionDescription.description);
            } catch (JSONException e) {
                e.printStackTrace();
            }
            mSocket.emit("SdpInfo", jsonObject.toString());
        }

        @Override
        public void onSetSuccess() {
            System.out.println("onSetSuccess");
        }

        @Override
        public void onCreateFailure(String s) {
            System.out.println("onCreateFailure");

        }

        @Override
        public void onSetFailure(String s) {
            System.out.println("onSetFailure");
        }
    }
}
